﻿using log4net;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using treeView.SqlDb.Services;

namespace treeView.SqlDb.Implements
{
    public class RepositoryBase<TEntity> : IRepository<TEntity>, IDisposable
        where TEntity : class
    {
        public virtual DbSet<TEntity> Entities => _context.Set<TEntity>();

        public List<TEntity> lTEntity = null;

        public List<TEntity> lTEntityInclude = null;

        /// <summary>
        /// DBBuilder.Options
        /// </summary>
        private readonly DbContextOptions<SCDBContext> _options;

        /// <summary>
        /// DBContext
        /// </summary>
        private readonly SCDBContext _context;

        public RepositoryBase(SCDBContext context)
        {
            _context = context;
        }
        public DbContext GetDbContext()
        {
            return _context;
        }

        /// <summary>
        /// 日志打印
        /// </summary>
        private readonly ILog _logger;


        public RepositoryBase(DbContextOptions<SCDBContext> options, ILog logger = null)
        {
            _options = options;
            _context = new SCDBContext(_options);
            _logger = logger;
            lTEntity = IListTEntity();
        }

        /// <summary>
        /// 实现泛型接口中的IQueryable<T>类型的 Table属性
        /// 标记为virtual是为了可以重写它
        /// </summary>
        /// 
        public virtual IQueryable<TEntity> Table
        {
            get
            {
                return this.Entities;
            }
        }

        #region 缓存策略
        /// <summary>
        /// 注：现系统业务，Labware数据贯穿全流程，更新添加管理现也只需单个程序员集中管理开发，缓存数据更适合现业务场景，
        /// Labware数据并没有达到10万条以上的使用高峰，这并不是一个耗材信息管理系统，无需担心缓存带来的数据压力。
        /// </summary>
        /// <returns></returns>
        public List<TEntity> IListTEntity()
        {
            if (lTEntity == null)
            {
                lTEntity = this.Entities.AsNoTracking().ToList();
            }

            return lTEntity;
        }
        /// <summary>
        /// 现系统业务，Labware数据贯穿全流程include模式。
        /// </summary>
        /// <returns></returns>
        public List<TEntity> IListTEntitysInclude(string modelName)
        {
            if (lTEntityInclude == null)
            {
                lTEntityInclude = this.Entities.Include(modelName).AsNoTracking().ToList();
            }

            return lTEntityInclude;
        }
        #endregion

        #region Sql范畴
        /// <summary>
        /// 这里也是返回的IQueryable接口的集合，
        /// 千万不要小看IQueryable接口，它是一种表达式树，可以延迟查询。
        /// 也就是说，在我们执行GetAllsql()之后，得到的是一个带有查询sql语句的表达式树结构，并没有去数据库执行查询，只有在我们ToList()的时候才会去查询数据库。
        /// </summary>
        public IQueryable<TEntity> GetAllSql()
        {
            return Table;
        }
        public IEnumerable<TEntity> GetAll()
        {
            return Table;
        }
        #endregion

        #region 单一ID传递
        public TEntity GetById(object id)
        {
            return this.Entities.Find(id);
        }
        #endregion

        #region 查找业务
        public List<Column> SelectBy<Column>(Expression<Func<TEntity, bool>> where, Expression<Func<TEntity, Column>> selectDto)
        {
            try
            {
                var allColumn = GetAllSql().Where(where).Select(selectDto).ToList();

                return allColumn;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        public int WhereCount(Expression<Func<TEntity, bool>> where)
        {
            int? count = GetAllSql().Where(where).AsNoTracking().Count();

            if (!count.HasValue)
                return 0;

            return count.Value;
        }

        public List<TEntity> WhereBySelfTakeSkip(Expression<Func<TEntity, bool>> where, int? PageIndex, int? PageSize)
        {
            if (PageIndex.HasValue && PageSize.HasValue)
                return GetAllSql().Where(where).Skip((PageIndex.Value - 1) * PageSize.Value).Take(PageSize.Value).AsNoTracking().ToList();
            else
                return GetAllSql().Where(where).AsNoTracking().ToList();
        }



        public async Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> where)
        {
            return await GetAllSql().Where(where).AsNoTracking().ToListAsync();
        }

        /// <summary>
        /// (集合)linq表达式，动态搜索参数，后截取数据(只可查询)
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public List<TEntity> ListWhereExpAsNoTracking(Expression<Func<TEntity, bool>> where)
        {
            lock (_queryobj)
            {
                return GetAllSql().Where(where).AsNoTracking().ToList();
            }
        }

        /// <summary>
        /// linq表达式，动态搜索参数，后截取数据(只可查询)
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public TEntity SingleWhereExpAsNoTracking(Expression<Func<TEntity, bool>> where)
        {
            lock (_queryobj)
            {
                return GetAllSql().AsNoTracking().FirstOrDefault(where);
            }
        }
        /// <summary>
        /// linq表达式，动态搜索参数，数据数据(更新配套使用)
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public TEntity SingleWhereExp(Expression<Func<TEntity, bool>> where)
        {
            lock (_queryobj)
            {
                return GetAllSql().FirstOrDefault(where);
            }
        }

        /// <summary>
        /// 动态搜索集合参数，数据追踪无条件(更新配套使用)
        /// </summary>
        /// <param name="where"></param>
        /// <returns></returns>
        public List<TEntity> GetAllList(Expression<Func<TEntity, bool>> where)
        {
            lock (_queryobj)
            {
                return GetAllSql().Where(where).ToList();
            }
        }


        /// <summary>
        /// 动态搜索单条参数，数据追踪无条件(更新配套使用)
        /// </summary>
        /// <returns></returns>
        public TEntity FirstOne()
        {
            lock (_queryobj)
            {
                return GetAllSql().FirstOrDefault();
            }
        }

        #endregion

        #region 同步增删改
        public bool Insert(TEntity model)
        {

            lock (_queryobj)
            {
                try
                {
                    if (model == null)
                        return false;

                    this.Entities.Add(model);
                    _context.SaveChanges();
                    CancelTrack(model);
                    return true;

                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }

        public bool Update(TEntity model)
        {
            lock (_queryobj)
            {
                try
                {
                    //model为空，抛空异常
                    if (model == null)
                        return false;


                    this.Entities.Update(model);
                    //直接保存了
                    _context.SaveChanges();
                    CancelTrack(model);
                    return true;

                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }

        /// <summary>
        /// 修改为 Modified 状态，为修改状态
        /// </summary>
        /// <param name="model"></param>
        /// <param name="keyName">主键名不为ID，用nameof(主键名)</param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public bool UpdateUnchanged(TEntity model, string keyName = null)
        {
            //try
            //{
            //    //model为空，抛空异常
            //    if (model == null)
            //        return false;

            //    //修改为 Modified 状态，为修改状态
            //    _context.Entry(model).State = Microsoft.EntityFrameworkCore.EntityState.Modified;

            //    //直接保存了
            //    _context.SaveChanges();

            //    return true;

            //}
            //catch (Exception ex)
            //{
            //    throw new Exception(ex.Message);
            //}
            lock (_queryobj)
            {
                try
                {
                    //model为空，抛空异常
                    if (model == null)
                        return false;


                    this.Entities.Update(model);
                    //直接保存了
                    _context.SaveChanges();
                    CancelTrack(model);
                    return true;

                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }



        public bool Delete(TEntity model)
        {
            lock (_queryobj)
            {
                try
                {
                    if (model == null)
                        return false;

                    this.Entities.Remove(model);
                    _context.SaveChanges();

                    return true;

                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }
        #endregion

        #region 同步批量增删改查
        public Tuple<bool, int> CreateRange(List<TEntity> list)
        {
            lock (_queryobj)
            {
                try
                {
                    if (list?.Count <= 0)
                        return new Tuple<bool, int>(false, 0);

                    this.Entities.AddRange(list);

                    var c = _context.SaveChanges();
                    return new Tuple<bool, int>(true, c);

                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }

        public Tuple<bool, int> DeleteRange(List<TEntity> list)
        {
            lock (_queryobj)
            {
                try
                {
                    if (list?.Count <= 0)
                        return new Tuple<bool, int>(false, 0);

                    this.Entities.RemoveRange(list);
                    var c = _context.SaveChanges();
                    return new Tuple<bool, int>(true, c);
                }
                catch (Exception ex)
                {
                    throw new Exception(ex.Message);
                }
            }
        }

        public Tuple<bool, int> UpdateRange(List<TEntity> list)
        {
            try
            {
                if (list?.Count <= 0)
                    return new Tuple<bool, int>(false, 0);


                foreach (var item in list)
                {
                    //更新时会更新所有的列
                    _context.Entry(item).State = Microsoft.EntityFrameworkCore.EntityState.Modified;
                }

                var c = _context.SaveChanges();
                return new Tuple<bool, int>(true, c);
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
        }

        private object _queryobj = new object();
        public List<TEntity> GetAsNoTrackingAllList()
        {
            lock (_queryobj)
            {
                return GetAllSql().AsNoTracking().ToList();
            }
        }

        public List<TEntity> GetAllList()
        {
            lock (_queryobj)
            {
                return GetAllSql().ToList();
            }
        }


        public void CancelTrack(TEntity currentEntry)
        {
            if (currentEntry != null)
            {
                _context.Entry(currentEntry).State = EntityState.Detached;
            }
        }

        #endregion

        #region 异步批量增删改查
        public async Task<List<TEntity>> GetAllListAsync()
        {
            return await GetAllSql().AsNoTracking().ToListAsync();
        }

        public async Task<Tuple<bool, int>> CreateRangeAsync(List<TEntity> list, CancellationToken cancellationToken = default)
        {
            if (list?.Count <= 0)
                return new Tuple<bool, int>(false, 0);

            await this.Entities.AddRangeAsync(list, cancellationToken);

            var c = await _context.SaveChangesAsync(cancellationToken);

            return new Tuple<bool, int>(true, c);
        }

        public async Task<Tuple<bool, int>> DeleteRangeAsync(List<TEntity> list, CancellationToken cancellationToken = default)
        {
            if (list?.Count <= 0)
                return new Tuple<bool, int>(false, 0);

            this.Entities.RemoveRange(list);

            var c = await _context.SaveChangesAsync(cancellationToken);

            return new Tuple<bool, int>(true, c);
        }

        public async Task<Tuple<bool, int>> UpdateRangeAsync(List<TEntity> list, CancellationToken cancellationToken = default)
        {
            if (list?.Count <= 0)
                return new Tuple<bool, int>(false, 0);

            this.Entities.UpdateRange(list);

            var c = await _context.SaveChangesAsync(cancellationToken);

            return new Tuple<bool, int>(true, c);
        }

        #endregion

        #region 内存释放
        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!this.disposed)
            {
                if (disposing)
                {
                    _context.Dispose();
                }
            }
            this.disposed = true;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
        #endregion


    }
}
